const async = require("async");//async模块 https://blog.csdn.net/zzwwjjdj1/article/details/51857959
const path = require('path');
const Url = require('url');
const colors = require('colors');
const _ = require('underscore');

class HelloWorldPlugin {
    constructor(options) {
        this.wpUploadOptions = {
            receiver: 'https://www.mocky.io/v2/5cc8019d300000980a055e76',//上传服务地址
            to: '/static',
            data: {test:1111}, //上传时额外的参数
            keepLocal: true, //是否在本地保留编译后静态资源文件
            test: function (filepath) {
                return filepath.indexOf("c.js") > -1;
            },
        };
    }
    apply(compiler) {
        let wpUploadOptions = this.wpUploadOptions;

        function _parseUrl (url, opt) {
            opt = opt || {};
            url = Url.parse(url);
            var ssl = url.protocol === 'https:';
            opt.host = opt.host || opt.hostname || ((ssl || url.protocol === 'http:') ? url.hostname : 'localhost');
            opt.port = opt.port || (url.port || (ssl ? 443 : 80));
            opt.path = opt.path || (url.pathname + (url.search ? url.search : ''));
            opt.method = opt.method || 'GET';
            opt.agent = opt.agent || false;
            return opt;
        }

        function _map(obj, callback, merge) {
            var index = 0;
            for (var key in obj) {
                if (obj.hasOwnProperty(key)) {
                    if (merge) {
                        callback[key] = obj[key];
                    } else if (callback(key, obj[key], index++)) {
                        break;
                    }
                }
            }
        }
        function _now (withoutMilliseconds) { //获取当前时间
            var d = new Date(),
                str;

            str = [
                d.getHours(),
                d.getMinutes(),
                d.getSeconds()
            ].join(':').replace(/\b\d\b/g, '0$&');
            if (!withoutMilliseconds) {
                str += '.' + ('00' + d.getMilliseconds()).substr(-3);
            }
            return str;
        }
        function _uploadFile(url, opt={}, data={}, content, subpath, callback){ //upload上传遵循RFC规范
            // utf8编码
            if (typeof content === 'string') {
                content = new Buffer(content, 'utf8'); //转为buffer传输
            } else if (!(content instanceof Buffer)) {
                console.error('unable to upload content [%s]', (typeof content));
            }
            let endl = '\r\n';
            let boundary = '-----np' + Math.random();
            let collect = [];
            _map(data, function(key, value) {
                collect.push('--' + boundary + endl);
                collect.push('Content-Disposition: form-data; name="' + key + '"' + endl);
                collect.push(endl);
                collect.push(value + endl);
            });
            collect.push('--' + boundary + endl);
            collect.push('Content-Disposition: form-data; name="' + (opt.uploadField || "file") + '"; filename="' + subpath + '"' + endl); //Content-Disposition: form-data; name="file"; filename="config.js"
            collect.push(endl);
            collect.push(content);
            collect.push(endl);
            collect.push('--' + boundary + '--' + endl);
            var length = 0;
            collect.forEach(function(ele) {
                if (typeof ele === 'string') {
                    length += new Buffer(ele).length;
                } else {
                    length += ele.length;
                }
            });

            opt.method = opt.method || 'POST';
            opt.headers = _.extend({
                'Content-Type': 'multipart/form-data; boundary=' + boundary,
                'Content-Length': length
            }, opt.headers || {});
            opt = _parseUrl(url, opt);

            var http = opt.protocol === 'https:' ? require('https') : require('http');
            var req = http.request(opt, function(res) {
                var status = res.statusCode;
                var body = '';
                res.on('data', function(chunk) {
                        body += chunk;
                }).on('end', function() {
                        if (status >= 200 && status < 300 || status === 304) {
                            callback(null, body);
                        } else {
                            callback(status);
                        }
                }).on('error', function(err) {
                        callback(err.message || err);
                });
            });
            collect.forEach(function(d) {
                req.write(d);
            });
            req.end();
        }
        function _upload(receiver, to, data, content, filepath, filename, callback){
            data = data || {};
            // 拼接获取远程上传的完整地址
            data['to'] = path.join(to, filename);
            // 路径兼容windows以及linux(or macos)
            data['to'] = data['to'].replace(/\\\\/g, '/').replace(/\\/g, '/');

            _uploadFile(receiver, null, data, content, filename,function(err,res){
                if (err || res.trim() != '0') {
                    callback('upload file [' + filepath + '] to [' + data['to'] + '] by receiver [' + receiver + '] error [' + (err || res) + ']');
                } else {
                    var time = '[' + _now(true) + ']';
                    process.stdout.write(
                        ' - '.green.bold +
                        time.grey + ' ' +
                        filepath.replace(/^\//, '') +
                        ' >> '.yellow.bold +
                        data['to'] +
                        '\n'
                    );
                    callback();
                }
            })

        }
        var onEmit = function (compilation, callback) {
            let steps = [];
            async.forEach(Object.keys(compilation.assets), function (file, cb) {
                let reTryCount = 2;
                // 目标文件名
                var targetFile = file;
                let queryStringIdx = targetFile.indexOf("?");
                // 去掉search参数
                if (queryStringIdx >= 0) {
                    targetFile = targetFile.substr(0, queryStringIdx);
                }

                var outputPath = compilation.getPath(compiler.outputPath),
                    outputFileSystem = compiler.outputFileSystem,
                    targetPath = outputFileSystem.join(outputPath, targetFile), //output path路径
                    content = compilation.assets[file].source(); //webpack编译后的源码

                if (!wpUploadOptions.keepLocal && !/\.html$/.test(targetFile)) {
                    //排除上传html文件
                    compilation.assets[file].existsAt = targetPath;
                    compilation.assets[file].emitted = true;
                }

                // 过滤条件处理
                if ("function" === typeof wpUploadOptions.test) {
                    //test为函数 将filename传入
                    if (!wpUploadOptions.test(targetFile)) {
                        return;
                    }
                    // 过滤条件为正则
                } else if (
                    Object.prototype.toString.call(wpUploadOptions.test) ===
                    "[object RegExp]"
                ) {
                    if (!wpUploadOptions.test.test(targetFile)) {
                        return;
                    }
                } else if (/\.html$/.test(targetFile)) {
                    return;
                }

                steps.push(function step(cb){
                    _upload(wpUploadOptions.receiver, wpUploadOptions.to, wpUploadOptions.data, content, targetPath, targetFile, function(error,re){
                        if(error){
                            if (wpUploadOptions.retry && !--reTryCount) {
                                throw new Error(error);
                            } else {
                                console.log('[retry uploading file] ' + targetPath);
                                step();
                            }
                        }else {
                            cb(null, re);
                        }
                    });
                });
            }.bind(this),function(err){
                if(err) {
                    console.error(err);
                    return callback(err);
                };
            });
            console.log('\n--------begin upload compiled resources--------\n');
            async.series(steps,function(err,results){
                if(err){
                    console.log(err);
                    callback(err);
                }
                console.log('\n--------upload finish!--------\n');
                callback();
            })
        };
        compiler.plugin("emit", onEmit);
    }
}
module.exports = HelloWorldPlugin;
